﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Cyss.Core;
using Cyss.Core.Repository;
using Common.Api.Entitys;
using Common.Api.Dtos;
using Cyss.Core.Repository.EF;
using System.ComponentModel.DataAnnotations;
using Cyss.Core.Models;

namespace Common.Api.Services
{
    /// <summary>
    /// 基础配置服务
    /// </summary>
    public class SettingService : BaseDefaultService<Setting, int>
    {
        #region 字段
        /// <summary>
        /// 基础配置仓储
        /// </summary>
        private readonly IRepository<Setting> _settingRepository;

        #endregion

        #region 构造函数

        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="settingRepository">基础配置 仓储</param>
        /// <param name="eventPublisher">事件发布者</param>
        public SettingService(IRepository<Setting> settingRepository) : base(settingRepository)
        {
            _settingRepository = settingRepository;
        }

        #endregion

        #region 基础配置方法


        /// <summary>
        ///  获取所有的  基础配置
        /// </summary>
        /// <param name="predicate">查询条件</param>
        /// <param name="IsNoTracking">是否进行实体跟踪,如果查询的对象不用于修改更新默认即可，实体跟踪会消耗资源</param>
        /// <returns>基础配置集合</returns>
        public virtual IList<Setting> GetSettings(Expression<Func<Setting, bool>> predicate = null, bool IsNoTracking = true)
        {
            var query = _settingRepository.Table;
            if (IsNoTracking)
            {
                query = _settingRepository.TableNoTracking;
            }
            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            return query.ToList();

        }

        /// <summary>
        /// 获取配置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual T GetSetting<T>() where T : BaseSettingEntity, new()
        {
            var typeName = typeof(T).Name;
            var settings = this.Gets(x => x.TypeName == typeName).ToList();
            var entity = new T();
            foreach (var property in typeof(T).GetProperties())
            {
                var setting = settings.FirstOrDefault(x => x.PropertyName.IsEquals(property.Name));
                if (setting != null)
                {
                    entity.SetPropertieValue(property.Name, Convert.ChangeType(setting.PropertyValue, property.PropertyType));
                }
            }
            return entity;
        }

        /// <summary>
        /// 获取配置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual object GetSetting(string TypeName)
        {
            var typeName = TypeName;
            var settings = this.Gets(x => x.TypeName == typeName).ToList();
            var type = AssembliesExtensions.GetTypesByBaseType<BaseSettingModel>().FirstOrDefault(x => x.Name.Replace("Model", "") == TypeName);
            var entity = Activator.CreateInstance(type);
            foreach (var property in type.GetProperties())
            {
                var setting = settings.FirstOrDefault(x => x.PropertyName.IsEquals(property.Name));
                if (setting != null)
                {
                    entity.SetPropertieValue(property.Name, Convert.ChangeType(setting.PropertyValue, property.PropertyType));
                }
            }
            return entity;
        }

        /// <summary>
        /// 更新配置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        public virtual void SetSeting<T>(T entity) where T : new()
        {
            var typeName = entity.GetType().Name;
            var settings = this.Gets(x => x.TypeName == typeName, false).ToList();
            List<Setting> newList = new List<Setting>();
            List<Setting> updateList = new List<Setting>();
            var propertyInfos = entity.GetType().GetProperties();
            foreach (var property in propertyInfos)
            {
                var setting = settings.FirstOrDefault(x => x.PropertyName.IsEquals(property.Name));
                if (setting != null)
                {
                    var newValue = entity.GetPropertieValue(property.Name)?.ToString();
                    var oldValue = setting.PropertyValue;
                    if (newValue != oldValue)
                    {
                        setting.PropertyValue = newValue;
                        setting.SetDefaultValue();
                        updateList.Add(setting);
                    }
                }
                else
                {
                    var newSetting = new Setting();
                    newSetting.TypeName = typeName;
                    newSetting.PropertyName = property.Name;
                    newSetting.PropertyValue = entity.GetPropertieValue(property.Name)?.ToString();
                    newSetting.CreateDate = DateTime.Now;
                    newSetting.CreateById = _workContext.User.Id;
                    newSetting.UpdateDate = DateTime.Now;
                    newSetting.UpdateById = _workContext.User.Id;
                    newSetting.SetDefaultValue();
                    newList.Add(newSetting);
                }
            }
            var delSettings = settings.Where(x => !propertyInfos.Select(x => x.Name).Contains(x.PropertyName)).ToList();
            if (newList.Any()) this.Insert(newList);
            if (updateList.Any()) this.Update(updateList);
            if (delSettings.Any()) this.Delete(delSettings);
        }

        /// <summary>
        /// 获取配置类型集合
        /// </summary>
        /// <returns></returns>
        public List<SettingModel> GetSettings(string TypeName)
        {
            var settings = this.Gets(x => x.TypeName == TypeName);
            List<SettingModel> models = new List<SettingModel>();
            var type = AssembliesExtensions.GetTypesByBaseType<BaseSettingModel>().FirstOrDefault(x => x.Name.Replace("Model", "") == TypeName);
            foreach (var propertyInfo in type.GetProperties())
            {
                var displayAttribute = propertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true).FirstOrDefault() as DisplayAttribute;
                var setting = settings.FirstOrDefault(x => x.PropertyName == propertyInfo.Name);
                if (setting == null)
                {
                    var settingModel = new SettingModel();
                    settingModel.TypeName = TypeName;
                    settingModel.PropertyName = propertyInfo.Name;
                    settingModel.PropertyType = propertyInfo.PropertyType.Name;
                    settingModel.PropertyTitle = displayAttribute == null ? propertyInfo.Name : displayAttribute.Name;
                    models.Add(settingModel);
                }
                else
                {
                    var settingModel = setting.ToModel<SettingModel>();
                    settingModel.PropertyType = propertyInfo.PropertyType.Name;
                    settingModel.PropertyTitle = displayAttribute == null ? propertyInfo.Name : displayAttribute.Name;
                    models.Add(settingModel);
                }
            }
            return models;
        }


        /// <summary>
        /// 更新配置
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public bool UpdateSettings(IEnumerable<Setting> models)
        {

            var Settings = this.Gets(x => models.Select(s => s.Id).Contains(x.Id), false);
            List<Setting> newSettings = new List<Setting>();
            List<Setting> upSettings = new List<Setting>();
            List<Setting> delSettings = new List<Setting>();

            foreach (var model in models)
            {

                var setting = Settings.FirstOrDefault(x => x.Id == model.Id);
                if (setting != null)
                {
                    if (setting.PropertyValue != model.PropertyValue)
                    {
                        setting.PropertyValue = model.PropertyValue;
                        upSettings.Add(setting);
                    }
                }
                else
                {
                    setting = new Setting();
                    setting.TypeName = model.TypeName;
                    setting.PropertyName = model.PropertyName;
                    setting.PropertyValue = model.PropertyValue;
                    setting.CreateDate = DateTime.Now;
                    setting.CreateById = _workContext.User.Id;
                    setting.UpdateDate = DateTime.Now;
                    setting.UpdateById = _workContext.User.Id;
                    setting.SetDefaultValue();
                    newSettings.Add(setting);
                }
            }
            delSettings = Settings.Where(x => !models.Select(x => x.PropertyName).Contains(x.PropertyName)).ToList();
            if (newSettings.Any()) this.Insert(newSettings);
            if (upSettings.Any()) this.Update(upSettings);
            if (delSettings.Any()) this.Delete(delSettings);
            return true;
        }

        #endregion

    }
}

